package dataserver

import (
	"config"
	"crypto/sha1"
	"encoding/json"
	"errors"
	"fmt"
	zp "gitee.com/sailinst/zhenwo/zhenwoproto"
	"github.com/DeanThompson/syncmap"
	"github.com/extrame/goblet"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"io"
	"log"
	"module"
	"net"
	"sort"
	"strings"
	"util/empower"
	"util/getrecord"
	"util/sendmsg"
	//zp "util/zhenwoproto"
)

var enterprise_infos *syncmap.SyncMap

type DServer struct {
}

func (s *DServer) Transmission(cx context.Context, in *zp.DatacheckRequest) (*zp.DatacheckReply, error) {
	log.Println("info", in)
	if in.ReqAction == "" {
		return &zp.DatacheckReply{}, errors.New("ReqAction is null.")
	}
	data := new(zp.Data)
	req_data := new(ReqData)
	req_data.IdCode = in.IdCode
	req_data.Name = in.Name
	req_data.ReqKey = in.ReqKey
	req_data.DataId = in.DataId
	req_data.Mobile = in.Mobile
	req_data.Appid = in.Appid
	req_data.FromId = in.FromId
	req_data.Sign = in.Sign
	req_data.ReqAction = in.ReqAction
	req_data.RecordKey = in.RecordKey
	req_data.Data = in.Data[:]

	response := new(zp.DatacheckReply)
	if _, _, err := req_data.CheckSign("one"); err != nil {
		data.Appid = in.Appid
		data.DataId = in.DataId
		data.IdCode = in.IdCode
		log.Println("check sign failed,err:", err)
		return zp.NewErrDataResponse("checksign_failed", err.Error()), errors.New("checksign_failed")
	}
	switch req_data.ReqAction {
	case "pushmsg":
		err := req_data.Pushmsg()
		if err != nil {
			return response.SetResponse(1003, "send_failed", err.Error()), errors.New("pushmsg_failed")
		}
		log.Println("pushmsg ok")
		return response.Success(), nil
	case "getrecord":
		if record, err := getrecord.Getrecord(req_data.IdCode, req_data.RecordKey); err != nil {
			return response.SetResponse(1004, "getrecord_failed", err.Error()), errors.New("getrecord_failed")
		} else {
			if record_byte, err := json.Marshal(record); err != nil {
				return response.ErrMsg1001("getrecord_failed", err.Error()), errors.New("getrecord_failed")
			} else {
				response.Success()
				response.Data = record_byte[:]
				return response, nil
			}
		}
	case "putrecord":
		record := new(getrecord.GetinfoRecords)
		if err := json.Unmarshal(in.Data, record); err != nil {
			return response.ErrMsg1001("putrecord_failed", err.Error()), errors.New("failed")
		}
		err := getrecord.Putrecord(record)
		if err != nil {
			response.ErrMsg1001("putrecord_failed", err.Error())
			return response, errors.New("failed")
		}
		return response.Success(), nil
		// 授权记录
	case "empower":
		if req_data.FromId == "" {
			req_data.FromId = empower.GetEnterpriseUuid(req_data.Appid)
		}
		switch req_data.ReqKey {

		case "getempower":
			record, err := empower.Getrecord(req_data.IdCode, req_data.FromId)
			if err != nil {
				return response.SetResponse(3001, "get_empower_failed", err.Error()), err
			}
			if record_byte, err := json.Marshal(record); err != nil {
				response.SetResponse(3002, "jsonUnmarshal_failed", err.Error())
				return response, errors.New("get_empower_failed")
			} else {
				response.Success()
				response.Data = record_byte[:]
				return response, nil
			}
		case "addempower":
			record := new(empower.EmpowerForm)
			if err := json.Unmarshal(in.Data, record); err != nil {
				return response.ErrMsg1001("add_empower_failed", err.Error()), errors.New("failed")
			}
			if err := empower.Putrecord(record); err != nil {
				response.SetResponse(3002, "add_failed", err.Error())
				return response, errors.New("failed")
			}
			return response.Success(), nil
		case "delempower":
			err := empower.Delrecord(req_data.IdCode, req_data.FromId)
			if err != nil {
				return response.SetResponse(3003, "delete_empower_failed", err.Error()), err
			}

			return response.Success(), nil

		case "update":
			record := new(empower.EmpowerForm)
			if err := json.Unmarshal(in.Data, record); err != nil {
				return response.ErrMsg1001("add_empower_failed", err.Error()), errors.New("failed")
			}
			if err := empower.Updaterecord(record); err != nil {
				response.SetResponse(3002, "update_failed", err.Error())
				return response, errors.New("failed")
			}
			return response.Success(), nil
		default:
			return response.SetResponse(2001, "请求参数错误", "错误的请求参数"), errors.New("getrecord_failed")
		}

	default:
		return response.SetResponse(1002, "request_failed", "error_request_key"), errors.New("error_request_key")
	}
	return response.SetResponse(9999, "unknow_error", "error"), errors.New("unknow")
}
func StartServer() {
	log.Println("port:", config.Config.ServerPort)
	listen, err := net.Listen("tcp", config.Config.ServerPort)
	if err != nil {
		log.Println("failed to listen:", err)
	}
	server := grpc.NewServer()
	// register server.
	zp.RegisterDataServiceServer(server, &DServer{})
	server.Serve(listen)
}

type ReqData struct {
	IdCode    string
	Name      string
	ReqKey    string
	DataId    string
	Mobile    string
	Appid     string
	FromId    string
	Sign      string
	ReqAction string
	RecordKey string
	Content   string
	Data      []byte
}

func (req *ReqData) Pushmsg() error {
	if req.Mobile == "" || req.Content == "" {
		return errors.New("mobile is null or content is null.")
	}
	return sendmsg.SendMessage(req.Mobile, req.Content)
}

type ResCode struct {
	Code int
	Msg  string
}

func (req *ReqData) CheckSign(reqtype string) (*module.Enterprise, *ResCode, error) {

	user := new(module.Enterprise)
	if len(req.Appid) == 0 {
		log.Println("resq", req)
		return nil, nil, errors.New("参数不正确")
	}
	if enterprise_infos != nil {
		if _, has := enterprise_infos.Get(req.Appid); !has {
			if has, err := goblet.DB.Where("appid = ?", req.Appid).Get(user); !has || err != nil {
				log.Println("err", err)
				return nil, nil, errors.New("Appid不存在")
			}
			user_byte, _ := json.Marshal(user)
			enterprise_infos.Set(req.Appid, user_byte)
		} else {
			if value, has := enterprise_infos.Get(req.Appid); has {
				json.Unmarshal(value.([]byte), user)
			}
		}
	} else {
		enterprise_infos = syncmap.NewWithShard(200)
		if has, err := goblet.DB.Where("appid= ?", req.Appid).Get(user); !has || err != nil {
			log.Println("err", err)
			return nil, nil, errors.New("Appid不存在")
		}
		user_byte, _ := json.Marshal(user)
		enterprise_infos.Set(req.Appid, user_byte)

	}
	if req.FromId == "" {
		req.FromId = user.Uuid
	}

	var arr []string
	switch req.ReqAction {
	case "normal":
		arr = append(arr, req.Appid, user.Key)
		if str, ok := checkSign(arr, req.Sign); ok {
			return user, nil, nil
		} else {
			log.Printf("sign error: need %s,but get %s \n ", str, req.Sign)
			return user, &ResCode{1000, "ok"}, errors.New("校验码不正确")
		}
	case "getrecord", "purecord":
		arr = append(arr, req.Appid, req.RecordKey, user.Key)
		if str, ok := checkSign(arr, req.Sign); ok {
			return user, nil, nil
		} else {
			log.Printf("sign error: need %s,but get %s \n ", str, req.Sign)
			return user, &ResCode{1000, "ok"}, errors.New("校验码不正确")
		}

	case "pushmsg": // 验证企业查看用户信息权限。

		arr = append(arr, req.Appid, req.Mobile, user.Key)
		if str, ok := checkSign(arr, req.Sign); ok {
			return user, nil, nil
		} else {
			log.Printf("sign error: need %s,but get %s \n ", str, req.Sign)
			return user, &ResCode{1000, "ok"}, errors.New("校验码不正确")
		}
	case "empower":
		arr = append(arr, req.IdCode, req.Appid, user.Key)
		if str, ok := checkSign(arr, req.Sign); ok {
			return user, nil, nil
		} else {
			log.Printf("this sign error: need %s,but get %s \n ", str, req.Sign)
			return user, &ResCode{1000, "ok"}, errors.New("校验码不正确")
		}
	}
	return user, &ResCode{1111, "bad request"}, errors.New("请求参数不正确")
}

func checkSign(array []string, sign string) (string, bool) {
	sort.Strings(array)
	s := sha1.New()
	io.WriteString(s, strings.Join(array, ""))
	str := fmt.Sprintf("%x", s.Sum(nil))
	return str, strings.EqualFold(str, sign)
}
